import { log } from "cc";


export enum LogType{
    Net =1,
    Model=2,
    Business=4,
    View=8,
    Config=16,
    Trace=32
}

// 这里是按位运算的，可以实现多个日志类型同时打开，比如：LogType.Net | LogType.Model | LogType.Business | LogType.View | LogType.Config | LogType.Trace
var names ={
    "1":"网络日志",
    "2":"模型日志",
    "4":"业务日志",
    "8":"视图日志",
    "16":"配置日志",
    "32":"跟踪日志"
}



export class Logger {


    //#region
    /**
     * 
     这里没有用到我想到的 getInstance，因为如果init方法用getinstance ,init方法就需要修改成public方法，不然无法调用

    private static _instance:Logger;

    public static getInstance(){
        if (!Logger._instance) {
            Logger._instance = new Logger();
        }
        return Logger._instance;
    }
     */

    //#endregion

    private static tags: number = 0;

    private static init(): void {
       this.tags = LogType.Net | LogType.Model | LogType.Business | LogType.View | LogType.Config | LogType.Trace;
    }


    static setTag(tag: LogType = null!){
        if (tag) {
            this.tags = tag;
        }
    }

    //用于打印代码执行的时间  ：start
    static start(description: string = "Time") : void {
        console.time(description);
    }

    //用于打印代码执行的时间  ：end
    static end(description: string = "Time") : void {
        console.timeEnd(description);
    }

    static table(msg:any,descrip?:string){
        if (!this.isOpen(LogType.Trace)) {
            return;
        }
        console.table(msg)
    }

    static trace(msg:any,color:string = "color:#ffffff;"){
        if (!this.isOpen(LogType.Trace)) {
            return;
        }
        const backLog = console.log || log;
        backLog.call(null,"%c%s%s",color,this.getDateString(),msg);
    }

    static logNet(msg:any,descrip?:string){
        this.orange(LogType.Net,msg,descrip);
    }
    
    /**
     * 打印数据层日志
     * @param msg       日志消息
     * @param describe  标题描述
     */
    static logModel(msg: any, describe?: string) {
        this.violet(LogType.Model, msg, describe);
    }

    /**
     * 打印业务层日志
     * @param msg       日志消息
     * @param describe  标题描述
     */
    static logBusiness(msg: any, describe?: string) {
        this.blue(LogType.Business, msg, describe);
    }

    /**
     * 打印视图日志
     * @param msg       日志消息
     * @param describe  标题描述
     */
    static logView(msg: any, describe?: string) {
        this.green(LogType.View, msg, describe);
    }

    /** 打印配置日志 */
    static logConfig(msg: any, describe?: string) {
        this.gray(LogType.Config, msg, describe);
    }
    private static isOpen(tag: LogType):boolean{
        return (this.tags & tag) != 0;
    }

    //橙色打印
    private static orange(tag: LogType,msg:any,descrip?:string){
        this.print(tag,msg,"color:#ee7700;",descrip)
    }
    
    // 紫色
    private static violet(tag: LogType, msg: any, describe?: string) {
        this.print(tag, msg, "color:Violet;", describe)
    }

    // 蓝色
    private static blue(tag: LogType, msg: any, describe?: string) {
        this.print(tag, msg, "color:#3a5fcd;", describe)
    }

    // 绿色
    private static green(tag: LogType, msg: any, describe?: string) {
        this.print(tag, msg, "color:green;", describe)
    }

    // 灰色
    private static gray(tag: LogType, msg: any, describe?: string) {
        this.print(tag, msg, "color:gray;", describe)
    }

 
    private static getDateString(): string {
        let timeStr = ""
        let d  = new Date()
        let str  = d.getHours().toString()
        timeStr += (str.length == 1 ? "0" + str : str) + ":"
        str = d.getMinutes().toString() 
        timeStr += (str.length == 1 ? "0" + str : str) + ":"
        str = d.getSeconds().toString() 
        timeStr += (str.length == 1 ? "0" + str : str) + "."
        str = d.getMilliseconds().toString() 
        timeStr += (str.length == 1 ? "00" + str : (str.length == 2 ? "0" + str : str)) 
        timeStr = "[" + timeStr + "]"
        return timeStr;
    }

    private static print(tag: LogType,msg:any,color:string,descrip?:string){
        if (!this.isOpen(tag)) return;
        const backLog = console.log || log;
        const type = names[tag];
        if (descrip) {
            backLog.call(null, "%c%s%s%s:%s%o", color, this.getDateString(), '[' + type + ']', this.stack(5), descrip, msg);
        }else{
            backLog.call(null, "%c%s%s%s:%o", color, this.getDateString(), '[' + type + ']', this.stack(5), msg);
        }
    }

    private static stack(index: number): string {

        const e = new Error();
        const lines = e.stack!.split("\n");
        const result: Array<any> = [];
        lines.forEach((line) => {
            line = line.substring(7);
            var lineBreak = line.split(" ");
            if (lineBreak.length < 2) {
                result.push(lineBreak[0]);
            }
            else {
                result.push({ [lineBreak[0]]: lineBreak[1] });
            }
        });

        let list: string[] = [];
        let splitList: Array<string> = [];
        if (index < result.length - 1) {
            let value: string;
            for (let a in result[index]) {
                splitList = a.split(".");

                if (splitList.length == 2) {
                    list = splitList.concat();
                }
                else {
                    value = result[index][a];
                    const start = value!.lastIndexOf("/");
                    const end = value!.lastIndexOf(".");
                    if (start > -1 && end > -1) {
                        const r = value!.substring(start + 1, end);
                        list.push(r);
                    }
                    else {
                        list.push(value);
                    }
                }
            }
        }

        if (list.length == 1) {
            return "[" + list[0] + ".ts]";
        }
        else if (list.length == 2) {
            return "[" + list[0] + ".ts->" + list[1] + "]";
        }
        return "";
    }


}

/**
 * 
 * Logger.getInstance().init()
*/

// @ts-ignore
Logger.init();